﻿//============================================================================================
/*
 * @brief 有限状态机 - 状态。
 * 
 *********************************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;

namespace Imagine.Infrastructure.FiniteStateMachines
{
    /// <summary>
    /// 有限状态机 - 状态。
    /// </summary>
    public interface IFSMState
    {
        string? Name { get; }
        void    BindEnterAction(Action  action);
        void    BindUpdateAction(Action action);
        void    BindExitAction(Action   action);
        void    Enter();
        void    Update();
        void    Exit();
        void    AddCondition(FSMCondition    condition, string? nextStateName);
        void    RemoveCondition(FSMCondition condition);
        bool    CheckCondition(out string?   nextStateName);
    }

    /// <summary>
    /// 有限状态机 - 状态。
    /// </summary>
    public class FsmState : IFSMState
    {
        private Dictionary<FSMCondition, string?> _conditionMaps;
        private Action                            _enterHandle;
        private Action                            _updateHandle;
        private Action                            _exitHandle;

        protected FsmState() => Name = GetType().FullName;
        protected FsmState(string? name) => Name = name;

        public static IFSMState Create(string? name) => new FsmState(name);

        public string? Name { get; private set; }

        public void BindEnterAction(Action  action) => _enterHandle = action;
        public void BindUpdateAction(Action action) => _updateHandle = action;
        public void BindExitAction(Action   action) => _exitHandle = action;

        public void Enter()
        {
            _enterHandle?.Invoke();
            OnEnter();
        }

        public void Update()
        {
            _updateHandle?.Invoke();
            OnUpdate();
        }

        public void Exit()
        {
            _exitHandle?.Invoke();
            OnExit();
        }

        protected virtual void OnEnter()  { }
        protected virtual void OnUpdate() { }
        protected virtual void OnExit()   { }

        public void AddCondition(FSMCondition condition, string? nextStateName)
        {
            if (condition == null ||
                string.IsNullOrEmpty(nextStateName))
                return;

            _conditionMaps ??= new Dictionary<FSMCondition, string?>();
            _conditionMaps.Add(condition, nextStateName);
        }

        public void RemoveCondition(FSMCondition condition)
        {
            if (_conditionMaps == null ||
                condition      == null)
                return;

            _conditionMaps.Remove(condition);
        }

        public bool CheckCondition(out string? nextStateName)
        {
            if (_conditionMaps == null)
            {
                nextStateName = string.Empty;
                return false;
            }

            foreach (var condition in _conditionMaps.Keys.Where(condition => condition.Condition()))
            {
                nextStateName = _conditionMaps[condition];
                return true;
            }

            nextStateName = string.Empty;
            return false;
        }
    }
}